package com.flute.icrawler.framework.framework.container;

import java.util.ArrayList;
import java.util.List;

import com.flute.icrawler.framework.framework.CrawlUrl;
import com.flute.tools.data.berkeleydb.BerkeleyDatabase;
import com.flute.tools.timer.IntervalExecutor;

public class BerkeleySortedUrlQueue {

	private BerkeleyDatabase urlDatabase;
	private BerkeleyDatabase keyDatabase;
	private List<CrawlUrl> tempUrls;
	private int size;
	private IntervalExecutor processExecutor;
	private static final int URL_TEMP_SIZE = 1000;

	public BerkeleySortedUrlQueue(String env, String dbName) {
		this.tempUrls = new ArrayList<CrawlUrl>();
		this.keyDatabase = BerkeleyManager.getBerkeleyDatabase(env, dbName
				+ "key", new UrlNormalBinding(), new UrlKeyBinding());
		this.urlDatabase = BerkeleyManager.getBerkeleyDatabase(env, dbName,
				new UrlKeyBinding());

		size = Long.valueOf(urlDatabase.size()).intValue();

		this.processExecutor = getProcessExecutor();
		this.processExecutor.setName("Bdb Delay Committer");
		processExecutor.setInterval(100);
		processExecutor.start();
	}

	public synchronized void addCrawlUrl(CrawlUrl url) {
		url.resetProcessingInfos();
		synchronized (tempUrls) {
			tempUrls.add(url);
		}
	}

	public void closeIntervalExecutor() {
		this.processExecutor.setFinish(true);
	}

	private IntervalExecutor getProcessExecutor() {
		return new IntervalExecutor() {

			@Override
			public void execute() {
				process();
			}
		};
	}

	private void process() {
		if (tempUrls.size() > URL_TEMP_SIZE || size == 0) {
			List<CrawlUrl> list = new ArrayList<CrawlUrl>();
			synchronized (tempUrls) {
				while (tempUrls.size() > 0) {
					list.add(tempUrls.get(0));
					tempUrls.remove(0);
				}
			}
			for (CrawlUrl url : list) {
				if (keyDatabase.contains(url)) {
					CrawlUrl storedUrl = (CrawlUrl) keyDatabase.search(url);
					if (storedUrl.getAdditionalUrlInformation().compareTo(
							url.getAdditionalUrlInformation()) > 0) {

						// keyDatabase.remove(url);
						keyDatabase.push(url);

						urlDatabase.remove(storedUrl);
						urlDatabase.push(url);
					}
				} else {
					keyDatabase.push(url);
					urlDatabase.push(url);
					size++;
				}
				flush();
			}
		}
	}

	public synchronized CrawlUrl getFirstCrawlUrl() {
		process();

		CrawlUrl url = (CrawlUrl) urlDatabase.pop();
		if (null != url) {
			keyDatabase.remove(url);
			size--;
		}

		// System.out.println(url.getUrl());
		// urlDatabase.printContent();

		return url;
	}

	public synchronized int size() {
		process();

		return size;
	}

	public boolean contains(CrawlUrl url) {
		return keyDatabase.contains(url);
	}

	public void clear() {
		size = 0;
		urlDatabase.clear();
		keyDatabase.clear();
	}

	public void flush() {
		urlDatabase.flush();
		keyDatabase.flush();
	}
}
